﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;

namespace CoNatural.Data.VisualStudio.AddIn.Forms {
   public partial class WizardForm : Form {
      public class WizardStep {
         public WizardStep(UserControl control, bool canFinish, bool canGoBack, string title, string[] instructions) {
            Control = control;
            CanFinish = canFinish;
            CanGoBack = canGoBack;
            Title = title;
            Instructions = instructions;
         }

         public UserControl Control { get; private set; }
         public bool CanFinish { get; private set; }
         public bool CanGoBack { get; private set; }
         public string Title { get; private set; }
         public string[] Instructions { get; private set; }
      }

      private int currentStepIndex;
      private WizardStep[] steps;

      public WizardForm() {
         InitializeComponent();
         backButton.Visible = false;
         nextButton.Visible = false;
         finishButton.Visible = false;
			progressBar.Visible = false;
			backgroundWorker.WorkerReportsProgress = true;
			backgroundWorker.WorkerSupportsCancellation = true;
			backgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
			backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker_ProgressChanged);
			backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted);
      }

		void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
			if(e.Error != null) {
				MessageBox.Show(e.Error.Message, Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
			else if(!e.Cancelled && e.Result as bool? == true) {
				// completed
				DialogResult = DialogResult.OK;
				Close();
				return;
			}

			cancelButton.Text = "Exit";
			RefreshState(true);
		}

		void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) {
			if(!progressBar.Visible)
				progressBar.Visible = true;
			progressBar.Value = e.ProgressPercentage;
		}

		void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) {
			e.Result = OnFinish(backgroundWorker);
		}

      protected void Initialize(params WizardStep[] steps) {
         this.steps = steps;
         foreach (WizardStep step in steps)
            step.Control.Parent = this;
         currentStepIndex = 0;
         RefreshState(false);
      }

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
		protected override void Dispose(bool disposing) {
			if(disposing) {
				backgroundWorker.DoWork -= new DoWorkEventHandler(backgroundWorker_DoWork);
				backgroundWorker.ProgressChanged -= new ProgressChangedEventHandler(backgroundWorker_ProgressChanged);
				backgroundWorker.RunWorkerCompleted -= new RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted);

				foreach(WizardStep step in steps)
					step.Control.Dispose();
            if(components != null)
				   components.Dispose();
			}
			base.Dispose(disposing);
		}

      protected virtual bool OnGoBack() { return true; }
      protected virtual bool OnGoNext() { return true; }
		protected virtual bool OnFinish(BackgroundWorker worker) { return true; }

      public int CurrentStepIndex {
         get { return currentStepIndex; }
      }

      public WizardStep CurrentStep {
         get { return steps[currentStepIndex]; }
      }

      private void RefreshState(bool visibilityOnly) {
         WizardStep currentStep = CurrentStep;

         stepTitleLabel.Text = currentStep.Title;
         stepInstructionsTextBox.Lines = currentStep.Instructions;
         
         backButton.Visible = currentStepIndex > 0;
         backButton.Enabled = currentStep.CanGoBack;

         nextButton.Visible = currentStepIndex < steps.Length - 1;

         finishButton.Visible = currentStep.CanFinish;

			progressBar.Visible = false;

			if(!visibilityOnly) {
				stepPanel.Controls.Clear();
				stepPanel.Controls.Add(currentStep.Control);
				currentStep.Control.Dock = DockStyle.Fill;
			}
      }
      
      private void backButton_Click(object sender, EventArgs e) {
         if (OnGoBack()) {
            currentStepIndex--;
            RefreshState(false);
         }
      }

      private void nextButton_Click(object sender, EventArgs e) {
         if (OnGoNext()) {
            currentStepIndex++;
            RefreshState(false);
         }
      }

      private void finishButton_Click(object sender, EventArgs e) {
			backButton.Visible = false;
			nextButton.Visible = false;
			finishButton.Visible = false;
			cancelButton.Text = "Cancel";

			backgroundWorker.RunWorkerAsync();
      }

      private void cancelButton_Click(object sender, EventArgs e) {
			if(backgroundWorker.IsBusy) {
				backgroundWorker.CancelAsync();
			}
			else {
				DialogResult = DialogResult.Cancel;
				Close();
			}
      }
   }
}
